Code copied from Ferroptosis_heatmaps.R and fixed to run
within this repo.
library(reshape2)
library(ggplot2)
Need help getting started? Try the R Graphics Cookbook: https://r-graphics.org
library(scales)
library(pheatmap)
library(gplots) # needed for color palettes, redblue(), colorRampPalette()
Attaching package: ‘gplots’
The following object is masked from ‘package:stats’:
lowess
SAVEPLOTS <- FALSE
load("../data/merged_countdata.RData") # object countdata
Ferr <- read.delim("../data/KEGGFerroptosis_hsa04216_06-25-18.txt", header=T, stringsAsFactors = F)
ferr_genes <- Ferr$GeneName # ferroptosis genes from KEGG (2018)
load("../data/RLD_SC-1,7,10_0,3,8d_20180701.RData") # object rld
Loading required package: DESeq2
Loading required package: S4Vectors
Warning: package ‘S4Vectors’ was built under R version 4.3.2
Loading required package: stats4
Loading required package: BiocGenerics
Attaching package: ‘BiocGenerics’
The following objects are masked from ‘package:stats’:
IQR, mad, sd, var, xtabs
The following objects are masked from ‘package:base’:
anyDuplicated, aperm, append, as.data.frame, basename, cbind, colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, order, paste, pmax, pmax.int, pmin, pmin.int, Position,
rank, rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply, union, unique, unsplit, which.max, which.min
Attaching package: ‘S4Vectors’
The following object is masked from ‘package:gplots’:
space
The following object is masked from ‘package:utils’:
findMatches
The following objects are masked from ‘package:base’:
expand.grid, I, unname
Loading required package: IRanges
Loading required package: GenomicRanges
Loading required package: GenomeInfoDb
Warning: package ‘GenomeInfoDb’ was built under R version 4.3.2
Loading required package: SummarizedExperiment
Warning: package ‘SummarizedExperiment’ was built under R version 4.3.2
Loading required package: MatrixGenerics
Loading required package: matrixStats
Attaching package: ‘MatrixGenerics’
The following objects are masked from ‘package:matrixStats’:
colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse, colCounts, colCummaxs, colCummins, colCumprods, colCumsums, colDiffs,
colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs, colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats, colProds,
colQuantiles, colRanges, colRanks, colSdDiffs, colSds, colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
colWeightedMeans, colWeightedMedians, colWeightedSds, colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet, rowCollapse,
rowCounts, rowCummaxs, rowCummins, rowCumprods, rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps, rowMadDiffs, rowMads,
rowMaxs, rowMeans2, rowMedians, rowMins, rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks, rowSdDiffs, rowSds, rowSums2,
rowTabulates, rowVarDiffs, rowVars, rowWeightedMads, rowWeightedMeans, rowWeightedMedians, rowWeightedSds, rowWeightedVars
Loading required package: Biobase
Welcome to Bioconductor
Vignettes contain introductory material; view with 'browseVignettes()'. To cite Bioconductor, see 'citation("Biobase")', and for
packages 'citation("pkgname")'.
Attaching package: ‘Biobase’
The following object is masked from ‘package:MatrixGenerics’:
rowMedians
The following objects are masked from ‘package:matrixStats’:
anyMissing, rowMedians
Another ferroptosis gene list from Wikipathways/GSEA: https://www.gsea-msigdb.org/gsea/msigdb/cards/WP_FERROPTOSIS.html
File downloaded 2024-01-14 and saved in
../data/WP_FERROPTOSIS.v2023.2.Hs.tsv
ferr_genes_wikipw_raw <- read.table('../data/WP_FERROPTOSIS.v2023.2.Hs.tsv', sep="\t", row.names=1)
ferr_genes_wikipw <- ferr_genes_wikipw_raw["GENE_SYMBOLS",]
ferr_genes_wikipw <- unlist(strsplit(ferr_genes_wikipw,","))
ferr_genes_wikipw <- ferr_genes_wikipw[ferr_genes_wikipw!=""]
Unclear why these genes should be excluded.
excl_genes <- c("ALOX15", "ACSL1", "ACSL3",
"ACSL5", "ACSL6", "TP53", "TF",
"CP", "MAP1LC3A", "MAP1LC3C",
"CYBB")
Define which gene set to use for all plots
object is ferrgenes_4plots. Setting to first item in
list will use newer and larger list of genes from wikipathways; setting
to item 2 will make output match previously generated plots.
ferr_genes_4plots <- list(ferr_genes_wikipw,ferr_genes)[[1]]
Process raw count data
Ferr <- Ferr[rowSums(is.na(Ferr)) == 0, ]
countdata_Fer <- countdata[ferr_genes_4plots,] # select genes here
Fer_samples = colsplit(colnames(countdata_Fer), pattern = "_", names = c("Population", "Time", "Replicate"))
Fer_plot = cbind(Fer_samples, t(countdata_Fer))
Fer_melt = melt(data = Fer_plot, id.vars = c("Population", "Time", "Replicate"), measure.vars = ferr_genes_4plots) # select genes here
Fer_dat = Rmisc::summarySE(Fer_melt, measurevar = "value", groupvars = c("Population", "Time", "variable"))
Fer_dat$Time = as.numeric(gsub("[^[:digit:]]","",Fer_dat$Time))
Low expressed genes
Add genes to excl_genes where all read counts < 16
(log2==4).
excl_genes <- union(excl_genes, rownames(countdata_Fer[which(apply(countdata_Fer, 1, function(x) all(x<=16))),]))
Plot change over time of BRAFi for each subclone
Changed plotting from linear to log2 scale for better visualization
of changes. Still raw (non-normalized) counts.
Fer_ggploted <- ggplot(Fer_dat, aes(x=Time, y=log2(value), group = interaction(variable, Population))) +
geom_line(linewidth=1.5, aes(color = Population)) +
geom_point(size = 1.5, aes(color = Population)) + facet_wrap(~variable, ncol = 5, scales = "free") +
geom_errorbar(aes(ymin=log2(value-sd), ymax=log2(value+sd), color = Population), width=.2, linewidth=1.5) +
theme_bw() + xlab("Time (days)") + ylab("Gene Counts") +
ggtitle("Ferroptosis gene signature") +
theme(legend.text = element_text(size = 10), legend.position = "right",
plot.title = element_text(size = 14, hjust = 0.5, face = "bold"), axis.text=element_text(size=12),
legend.title = element_text(size=12,face="bold"),
axis.title=element_text(size=12,face="bold"))
Fer_ggploted

if(SAVEPLOTS) ggsave("FerroptosisGeneSignature_rawCounts_SKMEL5sublines+treatment.pdf", width = 20, height = 25)
NOTE: This will overwrite objects with new data
Normalized data from DESeq2
normdata_Fer <- as.data.frame(assay(rld))[ferr_genes_4plots,]
Fer_match <- colsplit(colnames(normdata_Fer), pattern = "_", names = c("Population", "Time", "Replicate"))
Fer_plot <- cbind(Fer_match, t(normdata_Fer))
Fer_melt <- melt(data = Fer_plot, id.vars = c("Population", "Time", "Replicate"), measure.vars = unique(colnames(Fer_plot))[4:42])
Fer_dat <- Rmisc::summarySE(Fer_melt, measurevar = "value", groupvars = c("Population", "Time", "variable"))
Fer_dat$Time <- as.numeric(gsub("[^[:digit:]]","",Fer_dat$Time))
Remove excluded genes
Fer_dat <- Fer_dat[!Fer_dat$variable %in% excl_genes,]
Plot change over time of BRAFi for each subclone
Changed plotting from linear to log2 scale for better visualization
of changes.
Fer_ggploted <- ggplot(Fer_dat, aes(x=Time, y=value, group = interaction(variable, Population))) +
geom_line(linewidth=1.5, aes(color = Population)) +
geom_point(size = 1.5, aes(color = Population)) + facet_wrap(~variable, ncol = 5, scales = "free") +
geom_errorbar(aes(ymin=value-sd, ymax=value+sd, color = Population), width=.2, linewidth=1.5) +
theme_bw() + xlab("Time (days)") + ylab("Gene Counts") +
ggtitle("Ferroptosis gene signature") +
theme(legend.text = element_text(size = 10), legend.position = "right",
plot.title = element_text(size = 14, hjust = 0.5, face = "bold"), axis.text=element_text(size=12),
legend.title = element_text(size=12,face="bold"),
axis.title=element_text(size=12,face="bold"))
Fer_ggploted

if(SAVEPLOTS) ggsave("FerroptosisGeneSignature_normCounts_SKMEL5sublines+treatment.pdf", width = 20, height = 25)
# normdata_Fer
samples <- c("SC01_day0", "SC01_day3", "SC01_day8", "SC07_day0", "SC07_day3", "SC07_day8", "SC10_day0", "SC10_day3", "SC10_day8")
test <- sapply(samples, function(x) rowMeans(normdata_Fer[, grep(x, colnames(normdata_Fer))]))
test <- as.data.frame(test[complete.cases(test),])
allFC <- function(DEProc,startcol,endcol){
GE_fold <- DEProc[,-c(startcol:endcol)]
colvec <- colnames(DEProc)[startcol:endcol]
#Last index is a self comparison and is removed
for(k in 1:(length(colvec)-1)){
#Start with column that is 1 away from index
for(j in (k+1):length(colvec)){
compnam <- paste0(colvec[j],"/",colvec[k])
#Loop through each gene/row
for(i in 1:nrow(DEProc)){
f <- DEProc[i,colvec[j]]
h <- DEProc[i,colvec[k]]
GE_fold[i, compnam] <- log2(f/h)
}
}
}
return(GE_fold)
}
GE_fold <- allFC(test, 1,9)
ImpRat = c("SC01_day3/SC01_day0", "SC01_day8/SC01_day0",
"SC07_day3/SC07_day0", "SC07_day8/SC07_day0",
"SC10_day3/SC10_day0", "SC10_day8/SC10_day0")
Imp_fold <- GE_fold[,ImpRat]
Ferr <- read.delim("../data/KEGGFerroptosis_hsa04216_06-25-18.txt", header=T, stringsAsFactors = F)
Ferr_fold <- Imp_fold[rownames(Imp_fold) %in% ferr_genes_4plots,]
Ferr_fold$Gene <- rownames(Ferr_fold)
# clean column names
colnames(Ferr_fold) <- gsub("/SC[01][170]_day0","",colnames(Ferr_fold))
Ferr_fold_melt <- melt(Ferr_fold, id.vars = "Gene")
Ferr_fold_melt$Gene <- factor(Ferr_fold_melt$Gene, levels = rev(ferr_genes_4plots))
Ferr_fold_melt <- subset(Ferr_fold_melt, !Gene %in% excl_genes)
myplot <- ggplot(Ferr_fold_melt, aes(variable, Gene, fill = value)) +
geom_tile(color = "black") + theme_bw() +
scale_fill_gradientn(
colors=c("blue","white","red","red4"),
values=rescale(c(min(Ferr_fold_melt$value), 0, max(Ferr_fold_melt$value)/2, max(Ferr_fold_melt$value))),
limits=c(min(Ferr_fold_melt$value),max(Ferr_fold_melt$value)),
name = "Log2 Fold Change"
) + ylab("") + xlab("") +
theme(axis.text=element_text(size=10),
axis.text.x=element_text(angle = 90, hjust = 0),
axis.title=element_text(size=12),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank())
myplot

if(SAVEPLOTS) ggsave("Ferroptosis_FCHM_selected_wide.pdf", width = 8, height = 8)
par(mar=c(8,5,1,1), oma=c(3,1,0,0))
dtp <- as.matrix(Ferr_fold[,1:6])
dtp <- dtp[!rownames(dtp) %in% excl_genes,]
colnames(dtp) <- gsub("day","D",colnames(dtp))
mycolors <- colorRampPalette(c("darkblue","blue","white","red","red4"))(50)
gplots::heatmap.2(dtp, dendrogram="none", scale="none", Rowv=FALSE, Colv=FALSE, trace="none", tracecol=NA,
col=mycolors, srtCol=0, adjCol=0.5, colsep=c(2,4), offsetRow=-35, adjRow=c(1, 0.5),
cexCol = 0.2 + 0.75/log10(ncol(dtp)), cex.lab=0.5,
keysize=1, key.title=NA, key.ylab=NA, key.xlab="Log2 fold change", key.par=list(mar=c(6,3,5,1)))

Gene annotations
Manually assembled gene annotations.
annot <- c("Glutathione Metabolism",
"PUFA",
"Endosome Ferous Transfer",
"Ferroportin Export",
"Autolysosome Ferritin Storage",
"Ferric Acid Reduction",
"Heme Iron Transfer",
"Mitochondria")
annot_col <- c("orange","yellow","green","turquoise","purple","red","brown",grey(0.5))
ferr_genes_annot <- read.csv("../data/ferroptosis_gene_annot.csv")
ferr_genes_annot[ferr_genes_annot==""] <- NA
annots <- unique(unlist(apply(ferr_genes_annot[,grep("annot",colnames(ferr_genes_annot))],2,unique)))
annots <- annots[annots != "" & !is.na(annots)]
annots_col <- c("yellow","purple",grey(0.5),"black","red","orange","green","turquoise","brown")
names(annots_col) <- annots
dat <- Ferr_fold[order(match(Ferr_fold$Gene,ferr_genes_annot$gene_name)),]
fer <- list(genes=Ferr_fold$Gene,
fold_exp=dat[,1:6],
annot1=ferr_genes_annot[match(dat$Gene,ferr_genes_annot$gene_name),"annot1"],
annot2=ferr_genes_annot[match(dat$Gene,ferr_genes_annot$gene_name),"annot2"]
)
Using ComplexHeatmap()
if (!requireNamespace("BiocManager", quietly=TRUE))
install.packages("BiocManager")
BiocManager::install("ComplexHeatmap")
library(ComplexHeatmap)
ht_opt(
legend_title_gp = gpar(fontsize = 8, fontface = "bold"),
legend_labels_gp = gpar(fontsize = 8),
heatmap_column_names_gp = gpar(fontsize = 8),
heatmap_column_title_gp = gpar(fontsize = 10),
heatmap_row_title_gp = gpar(fontsize = 8)
)
ht_list = Heatmap(as.matrix(fer$fold_exp), name = "Log2 fold expression",
width = unit(8, "cm"),
cluster_rows = FALSE, cluster_columns = FALSE,
row_names_side = "left", row_names_gp = gpar(fontsize = 8)) +
Heatmap(fer$annot1, name = "GO:1", col = annots_col, width = unit(5, "mm")) +
Heatmap(fer$annot2, name = "GO:2", col = annots_col, width = unit(5, "mm"))
ht_list

LS0tCnRpdGxlOiAiQ29udmVydGluZyBGZXJyb3B0b3NpcyBoZWF0bWFwIGNvZGUgdG8gbm90ZWJvb2siCm91dHB1dDogaHRtbF9ub3RlYm9vawphdXRob3I6IERhcnJlbiBUeXNvbgpkYXRlOiAyMDI0LTAxLTE0Ci0tLQoKQ29kZSBjb3BpZWQgZnJvbSBgRmVycm9wdG9zaXNfaGVhdG1hcHMuUmAgYW5kIGZpeGVkIHRvIHJ1biB3aXRoaW4gdGhpcyByZXBvLgoKCmBgYHtyfQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KHBoZWF0bWFwKQpsaWJyYXJ5KGdwbG90cykgIyBuZWVkZWQgZm9yIGNvbG9yIHBhbGV0dGVzLCByZWRibHVlKCksIGNvbG9yUmFtcFBhbGV0dGUoKQpgYGAKCgpgYGB7cn0KU0FWRVBMT1RTIDwtIEZBTFNFCmBgYAoKCmBgYHtyIExvYWQgZGF0YX0KbG9hZCgiLi4vZGF0YS9tZXJnZWRfY291bnRkYXRhLlJEYXRhIikgIyBvYmplY3QgY291bnRkYXRhCkZlcnIgPC0gcmVhZC5kZWxpbSgiLi4vZGF0YS9LRUdHRmVycm9wdG9zaXNfaHNhMDQyMTZfMDYtMjUtMTgudHh0IiwgaGVhZGVyPVQsIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKQpmZXJyX2dlbmVzIDwtIEZlcnIkR2VuZU5hbWUgICMgZmVycm9wdG9zaXMgZ2VuZXMgZnJvbSBLRUdHICgyMDE4KQpsb2FkKCIuLi9kYXRhL1JMRF9TQy0xLDcsMTBfMCwzLDhkXzIwMTgwNzAxLlJEYXRhIikgICMgb2JqZWN0IHJsZApgYGAKCkFub3RoZXIgZmVycm9wdG9zaXMgZ2VuZSBsaXN0IGZyb20gV2lraXBhdGh3YXlzL0dTRUE6IGh0dHBzOi8vd3d3LmdzZWEtbXNpZ2RiLm9yZy9nc2VhL21zaWdkYi9jYXJkcy9XUF9GRVJST1BUT1NJUy5odG1sCkZpbGUgZG93bmxvYWRlZCAyMDI0LTAxLTE0IGFuZCBzYXZlZCBpbiBgLi4vZGF0YS9XUF9GRVJST1BUT1NJUy52MjAyMy4yLkhzLnRzdmAKCmBgYHtyfQpmZXJyX2dlbmVzX3dpa2lwd19yYXcgPC0gcmVhZC50YWJsZSgnLi4vZGF0YS9XUF9GRVJST1BUT1NJUy52MjAyMy4yLkhzLnRzdicsIHNlcD0iXHQiLCByb3cubmFtZXM9MSkKZmVycl9nZW5lc193aWtpcHcgPC0gZmVycl9nZW5lc193aWtpcHdfcmF3WyJHRU5FX1NZTUJPTFMiLF0KZmVycl9nZW5lc193aWtpcHcgPC0gdW5saXN0KHN0cnNwbGl0KGZlcnJfZ2VuZXNfd2lraXB3LCIsIikpCmZlcnJfZ2VuZXNfd2lraXB3IDwtIGZlcnJfZ2VuZXNfd2lraXB3W2ZlcnJfZ2VuZXNfd2lraXB3IT0iIl0KYGBgCgoKVW5jbGVhciB3aHkgdGhlc2UgZ2VuZXMgc2hvdWxkIGJlIGV4Y2x1ZGVkLgpgYGB7cn0KZXhjbF9nZW5lcyA8LSBjKCJBTE9YMTUiLCAiQUNTTDEiLCAiQUNTTDMiLAogICAgICAgICAgICAgICAgIkFDU0w1IiwgIkFDU0w2IiwgIlRQNTMiLCAiVEYiLAogICAgICAgICAgICAgICAgIkNQIiwgIk1BUDFMQzNBIiwgIk1BUDFMQzNDIiwKICAgICAgICAgICAgICAgICJDWUJCIikKYGBgCgojIyMgRGVmaW5lIHdoaWNoIGdlbmUgc2V0IHRvIHVzZSBmb3IgYWxsIHBsb3RzCm9iamVjdCBpcyBgZmVycmdlbmVzXzRwbG90c2AuIFNldHRpbmcgdG8gZmlyc3QgaXRlbSBpbiBsaXN0IHdpbGwgdXNlIG5ld2VyIGFuZCBsYXJnZXIgbGlzdCBvZiBnZW5lcyBmcm9tIHdpa2lwYXRod2F5czsgc2V0dGluZyB0byBpdGVtIDIgd2lsbCBtYWtlIG91dHB1dCBtYXRjaCBwcmV2aW91c2x5IGdlbmVyYXRlZCBwbG90cy4KYGBge3J9CmZlcnJfZ2VuZXNfNHBsb3RzIDwtIGxpc3QoZmVycl9nZW5lc193aWtpcHcsZmVycl9nZW5lcylbWzFdXQpgYGAKCgojIyMgUHJvY2VzcyByYXcgY291bnQgZGF0YQpgYGB7cn0KRmVyciA8LSBGZXJyW3Jvd1N1bXMoaXMubmEoRmVycikpID09IDAsIF0KCmNvdW50ZGF0YV9GZXIgPC0gY291bnRkYXRhW2ZlcnJfZ2VuZXNfNHBsb3RzLF0gICMgc2VsZWN0IGdlbmVzIGhlcmUKCkZlcl9zYW1wbGVzID0gY29sc3BsaXQoY29sbmFtZXMoY291bnRkYXRhX0ZlciksIHBhdHRlcm4gPSAiXyIsIG5hbWVzID0gYygiUG9wdWxhdGlvbiIsICJUaW1lIiwgIlJlcGxpY2F0ZSIpKQpGZXJfcGxvdCA9IGNiaW5kKEZlcl9zYW1wbGVzLCB0KGNvdW50ZGF0YV9GZXIpKQpGZXJfbWVsdCA9IG1lbHQoZGF0YSA9IEZlcl9wbG90LCBpZC52YXJzID0gYygiUG9wdWxhdGlvbiIsICJUaW1lIiwgIlJlcGxpY2F0ZSIpLCBtZWFzdXJlLnZhcnMgPSBmZXJyX2dlbmVzXzRwbG90cykgICMgc2VsZWN0IGdlbmVzIGhlcmUKRmVyX2RhdCA9IFJtaXNjOjpzdW1tYXJ5U0UoRmVyX21lbHQsIG1lYXN1cmV2YXIgPSAidmFsdWUiLCBncm91cHZhcnMgPSBjKCJQb3B1bGF0aW9uIiwgIlRpbWUiLCAidmFyaWFibGUiKSkKRmVyX2RhdCRUaW1lID0gYXMubnVtZXJpYyhnc3ViKCJbXls6ZGlnaXQ6XV0iLCIiLEZlcl9kYXQkVGltZSkpCmBgYAoKIyMjIExvdyBleHByZXNzZWQgZ2VuZXMKQWRkIGdlbmVzIHRvIGBleGNsX2dlbmVzYCB3aGVyZSBhbGwgcmVhZCBjb3VudHMgPCAxNiAobG9nMj09NCkuCmBgYHtyfQpleGNsX2dlbmVzIDwtIHVuaW9uKGV4Y2xfZ2VuZXMsIHJvd25hbWVzKGNvdW50ZGF0YV9GZXJbd2hpY2goYXBwbHkoY291bnRkYXRhX0ZlciwgMSwgZnVuY3Rpb24oeCkgYWxsKHg8PTE2KSkpLF0pKQpgYGAKCgojIyMgUGxvdCBjaGFuZ2Ugb3ZlciB0aW1lIG9mIEJSQUZpIGZvciBlYWNoIHN1YmNsb25lCkNoYW5nZWQgcGxvdHRpbmcgZnJvbSBsaW5lYXIgdG8gbG9nMiBzY2FsZSBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24gb2YgY2hhbmdlcy4gU3RpbGwgcmF3IChub24tbm9ybWFsaXplZCkgY291bnRzLgpgYGB7ciBmaWcuaGVpZ2h0PTI1LCBmaWcud2lkdGg9MjB9CkZlcl9nZ3Bsb3RlZCA8LSBnZ3Bsb3QoRmVyX2RhdCwgYWVzKHg9VGltZSwgeT1sb2cyKHZhbHVlKSwgZ3JvdXAgPSBpbnRlcmFjdGlvbih2YXJpYWJsZSwgUG9wdWxhdGlvbikpKSArIAogIGdlb21fbGluZShsaW5ld2lkdGg9MS41LCBhZXMoY29sb3IgPSBQb3B1bGF0aW9uKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAxLjUsIGFlcyhjb2xvciA9IFBvcHVsYXRpb24pKSArIGZhY2V0X3dyYXAofnZhcmlhYmxlLCBuY29sID0gNSwgc2NhbGVzID0gImZyZWUiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb2cyKHZhbHVlLXNkKSwgeW1heD1sb2cyKHZhbHVlK3NkKSwgY29sb3IgPSBQb3B1bGF0aW9uKSwgd2lkdGg9LjIsIGxpbmV3aWR0aD0xLjUpICsKICB0aGVtZV9idygpICsgeGxhYigiVGltZSAoZGF5cykiKSArIHlsYWIoIkdlbmUgQ291bnRzIikgKwogIGdndGl0bGUoIkZlcnJvcHRvc2lzIGdlbmUgc2lnbmF0dXJlIikgKwogIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsIAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiksIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTIsZmFjZT0iYm9sZCIpLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIsZmFjZT0iYm9sZCIpKQoKRmVyX2dncGxvdGVkCgppZihTQVZFUExPVFMpIGdnc2F2ZSgiRmVycm9wdG9zaXNHZW5lU2lnbmF0dXJlX3Jhd0NvdW50c19TS01FTDVzdWJsaW5lcyt0cmVhdG1lbnQucGRmIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMjUpCmBgYAoKCiMjIyBOT1RFOiBUaGlzIHdpbGwgb3ZlcndyaXRlIG9iamVjdHMgd2l0aCBuZXcgZGF0YQpOb3JtYWxpemVkIGRhdGEgZnJvbSBERVNlcTIKYGBge3J9Cm5vcm1kYXRhX0ZlciA8LSBhcy5kYXRhLmZyYW1lKGFzc2F5KHJsZCkpW2ZlcnJfZ2VuZXNfNHBsb3RzLF0KCkZlcl9tYXRjaCA8LSBjb2xzcGxpdChjb2xuYW1lcyhub3JtZGF0YV9GZXIpLCBwYXR0ZXJuID0gIl8iLCBuYW1lcyA9IGMoIlBvcHVsYXRpb24iLCAiVGltZSIsICJSZXBsaWNhdGUiKSkKRmVyX3Bsb3QgPC0gY2JpbmQoRmVyX21hdGNoLCB0KG5vcm1kYXRhX0ZlcikpCkZlcl9tZWx0IDwtIG1lbHQoZGF0YSA9IEZlcl9wbG90LCBpZC52YXJzID0gYygiUG9wdWxhdGlvbiIsICJUaW1lIiwgIlJlcGxpY2F0ZSIpLCBtZWFzdXJlLnZhcnMgPSB1bmlxdWUoY29sbmFtZXMoRmVyX3Bsb3QpKVs0OjQyXSkKRmVyX2RhdCA8LSBSbWlzYzo6c3VtbWFyeVNFKEZlcl9tZWx0LCBtZWFzdXJldmFyID0gInZhbHVlIiwgZ3JvdXB2YXJzID0gYygiUG9wdWxhdGlvbiIsICJUaW1lIiwgInZhcmlhYmxlIikpCkZlcl9kYXQkVGltZSA8LSBhcy5udW1lcmljKGdzdWIoIlteWzpkaWdpdDpdXSIsIiIsRmVyX2RhdCRUaW1lKSkKYGBgCgojIyMgUmVtb3ZlIGV4Y2x1ZGVkIGdlbmVzCmBgYHtyfQpGZXJfZGF0IDwtIEZlcl9kYXRbIUZlcl9kYXQkdmFyaWFibGUgJWluJSBleGNsX2dlbmVzLF0KYGBgCgojIyMgUGxvdCBjaGFuZ2Ugb3ZlciB0aW1lIG9mIEJSQUZpIGZvciBlYWNoIHN1YmNsb25lCkNoYW5nZWQgcGxvdHRpbmcgZnJvbSBsaW5lYXIgdG8gbG9nMiBzY2FsZSBmb3IgYmV0dGVyIHZpc3VhbGl6YXRpb24gb2YgY2hhbmdlcy4KYGBge3IgZmlnLmhlaWdodD0yNSwgZmlnLndpZHRoPTIwfQpGZXJfZ2dwbG90ZWQgPC0gZ2dwbG90KEZlcl9kYXQsIGFlcyh4PVRpbWUsIHk9dmFsdWUsIGdyb3VwID0gaW50ZXJhY3Rpb24odmFyaWFibGUsIFBvcHVsYXRpb24pKSkgKyAKICBnZW9tX2xpbmUobGluZXdpZHRoPTEuNSwgYWVzKGNvbG9yID0gUG9wdWxhdGlvbikpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMS41LCBhZXMoY29sb3IgPSBQb3B1bGF0aW9uKSkgKyBmYWNldF93cmFwKH52YXJpYWJsZSwgbmNvbCA9IDUsIHNjYWxlcyA9ICJmcmVlIikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49dmFsdWUtc2QsIHltYXg9dmFsdWUrc2QsIGNvbG9yID0gUG9wdWxhdGlvbiksIHdpZHRoPS4yLCBsaW5ld2lkdGg9MS41KSArCiAgdGhlbWVfYncoKSArIHhsYWIoIlRpbWUgKGRheXMpIikgKyB5bGFiKCJHZW5lIENvdW50cyIpICsKICBnZ3RpdGxlKCJGZXJyb3B0b3NpcyBnZW5lIHNpZ25hdHVyZSIpICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLCBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCAKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCwgaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLCBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEyLGZhY2U9ImJvbGQiKSwKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEyLGZhY2U9ImJvbGQiKSkKCkZlcl9nZ3Bsb3RlZAoKaWYoU0FWRVBMT1RTKSBnZ3NhdmUoIkZlcnJvcHRvc2lzR2VuZVNpZ25hdHVyZV9ub3JtQ291bnRzX1NLTUVMNXN1YmxpbmVzK3RyZWF0bWVudC5wZGYiLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAyNSkKYGBgCgoKYGBge3J9CiMgbm9ybWRhdGFfRmVyCnNhbXBsZXMgPC0gYygiU0MwMV9kYXkwIiwgIlNDMDFfZGF5MyIsICJTQzAxX2RheTgiLCAiU0MwN19kYXkwIiwgIlNDMDdfZGF5MyIsICJTQzA3X2RheTgiLCAiU0MxMF9kYXkwIiwgIlNDMTBfZGF5MyIsICJTQzEwX2RheTgiKQp0ZXN0IDwtIHNhcHBseShzYW1wbGVzLCBmdW5jdGlvbih4KSByb3dNZWFucyhub3JtZGF0YV9GZXJbLCBncmVwKHgsIGNvbG5hbWVzKG5vcm1kYXRhX0ZlcikpXSkpCnRlc3QgPC0gYXMuZGF0YS5mcmFtZSh0ZXN0W2NvbXBsZXRlLmNhc2VzKHRlc3QpLF0pCgoKCmFsbEZDIDwtIGZ1bmN0aW9uKERFUHJvYyxzdGFydGNvbCxlbmRjb2wpeyAKICBHRV9mb2xkIDwtIERFUHJvY1ssLWMoc3RhcnRjb2w6ZW5kY29sKV0KICBjb2x2ZWMgPC0gY29sbmFtZXMoREVQcm9jKVtzdGFydGNvbDplbmRjb2xdCiAgCiAgI0xhc3QgaW5kZXggaXMgYSBzZWxmIGNvbXBhcmlzb24gYW5kIGlzIHJlbW92ZWQKICBmb3IoayBpbiAxOihsZW5ndGgoY29sdmVjKS0xKSl7CiAgICAjU3RhcnQgd2l0aCBjb2x1bW4gdGhhdCBpcyAxIGF3YXkgZnJvbSBpbmRleCAKICAgIGZvcihqIGluIChrKzEpOmxlbmd0aChjb2x2ZWMpKXsKICAgICAgY29tcG5hbSA8LSBwYXN0ZTAoY29sdmVjW2pdLCIvIixjb2x2ZWNba10pCiAgICAgICNMb29wIHRocm91Z2ggZWFjaCBnZW5lL3JvdyAgCiAgICAgIGZvcihpIGluIDE6bnJvdyhERVByb2MpKXsKICAgICAgICBmIDwtIERFUHJvY1tpLGNvbHZlY1tqXV0KICAgICAgICBoIDwtIERFUHJvY1tpLGNvbHZlY1trXV0KICAgICAgICBHRV9mb2xkW2ksIGNvbXBuYW1dIDwtIGxvZzIoZi9oKQogICAgIH0KICAgIH0KICB9CgogIHJldHVybihHRV9mb2xkKQp9CgpHRV9mb2xkIDwtIGFsbEZDKHRlc3QsIDEsOSkKSW1wUmF0ID0gYygiU0MwMV9kYXkzL1NDMDFfZGF5MCIsICJTQzAxX2RheTgvU0MwMV9kYXkwIiwgCiAgICAgICAgICAgIlNDMDdfZGF5My9TQzA3X2RheTAiLCAiU0MwN19kYXk4L1NDMDdfZGF5MCIsIAogICAgICAgICAgICJTQzEwX2RheTMvU0MxMF9kYXkwIiwgIlNDMTBfZGF5OC9TQzEwX2RheTAiKQpJbXBfZm9sZCA8LSBHRV9mb2xkWyxJbXBSYXRdCgpGZXJyIDwtIHJlYWQuZGVsaW0oIi4uL2RhdGEvS0VHR0ZlcnJvcHRvc2lzX2hzYTA0MjE2XzA2LTI1LTE4LnR4dCIsIGhlYWRlcj1ULCBzdHJpbmdzQXNGYWN0b3JzID0gRikKRmVycl9mb2xkIDwtIEltcF9mb2xkW3Jvd25hbWVzKEltcF9mb2xkKSAlaW4lIGZlcnJfZ2VuZXNfNHBsb3RzLF0KCkZlcnJfZm9sZCRHZW5lIDwtIHJvd25hbWVzKEZlcnJfZm9sZCkKCiMgY2xlYW4gY29sdW1uIG5hbWVzCmNvbG5hbWVzKEZlcnJfZm9sZCkgPC0gZ3N1YigiL1NDWzAxXVsxNzBdX2RheTAiLCIiLGNvbG5hbWVzKEZlcnJfZm9sZCkpCmBgYAoKIyMjIApgYGB7cn0KRmVycl9mb2xkX21lbHQgPC0gbWVsdChGZXJyX2ZvbGQsIGlkLnZhcnMgPSAiR2VuZSIpCkZlcnJfZm9sZF9tZWx0JEdlbmUgPC0gZmFjdG9yKEZlcnJfZm9sZF9tZWx0JEdlbmUsIGxldmVscyA9IHJldihmZXJyX2dlbmVzXzRwbG90cykpCgpGZXJyX2ZvbGRfbWVsdCA8LSBzdWJzZXQoRmVycl9mb2xkX21lbHQsICFHZW5lICVpbiUgZXhjbF9nZW5lcykKYGBgCgoKYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KbXlwbG90IDwtIGdncGxvdChGZXJyX2ZvbGRfbWVsdCwgYWVzKHZhcmlhYmxlLCBHZW5lLCBmaWxsID0gdmFsdWUpKSArIAogIGdlb21fdGlsZShjb2xvciA9ICJibGFjayIpICsgdGhlbWVfYncoKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudG4oCiAgICBjb2xvcnM9YygiYmx1ZSIsIndoaXRlIiwicmVkIiwicmVkNCIpLAogICAgdmFsdWVzPXJlc2NhbGUoYyhtaW4oRmVycl9mb2xkX21lbHQkdmFsdWUpLCAwLCBtYXgoRmVycl9mb2xkX21lbHQkdmFsdWUpLzIsIG1heChGZXJyX2ZvbGRfbWVsdCR2YWx1ZSkpKSwKICAgIGxpbWl0cz1jKG1pbihGZXJyX2ZvbGRfbWVsdCR2YWx1ZSksbWF4KEZlcnJfZm9sZF9tZWx0JHZhbHVlKSksCiAgICBuYW1lID0gIkxvZzIgRm9sZCBDaGFuZ2UiCiAgKSArIHlsYWIoIiIpICsgeGxhYigiIikgKyAKICB0aGVtZShheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDApLAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTIpLAogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIAogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpCgpteXBsb3QKaWYoU0FWRVBMT1RTKSBnZ3NhdmUoIkZlcnJvcHRvc2lzX0ZDSE1fc2VsZWN0ZWRfd2lkZS5wZGYiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9CnBhcihtYXI9Yyg4LDUsMSwxKSwgb21hPWMoMywxLDAsMCkpCmR0cCA8LSBhcy5tYXRyaXgoRmVycl9mb2xkWywxOjZdKQpkdHAgPC0gZHRwWyFyb3duYW1lcyhkdHApICVpbiUgZXhjbF9nZW5lcyxdCmNvbG5hbWVzKGR0cCkgPC0gZ3N1YigiZGF5IiwiRCIsY29sbmFtZXMoZHRwKSkgCm15Y29sb3JzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiZGFya2JsdWUiLCJibHVlIiwid2hpdGUiLCJyZWQiLCJyZWQ0IikpKDUwKQoKZ3Bsb3RzOjpoZWF0bWFwLjIoZHRwLCBkZW5kcm9ncmFtPSJub25lIiwgc2NhbGU9Im5vbmUiLCBSb3d2PUZBTFNFLCBDb2x2PUZBTFNFLCB0cmFjZT0ibm9uZSIsIHRyYWNlY29sPU5BLAogICAgICAgICAgICAgICAgICBjb2w9bXljb2xvcnMsIHNydENvbD0wLCBhZGpDb2w9MC41LCBjb2xzZXA9YygyLDQpLCBvZmZzZXRSb3c9LTM1LCBhZGpSb3c9YygxLCAwLjUpLAogICAgICAgICAgICAgICAgICBjZXhDb2wgPSAwLjIgKyAwLjc1L2xvZzEwKG5jb2woZHRwKSksIGNleC5sYWI9MC41LAogICAgICAgICAgICAgICAgICBrZXlzaXplPTEsIGtleS50aXRsZT1OQSwga2V5LnlsYWI9TkEsIGtleS54bGFiPSJMb2cyIGZvbGQgY2hhbmdlIiwga2V5LnBhcj1saXN0KG1hcj1jKDYsMyw1LDEpKSkKYGBgCgojIyMgR2VuZSBhbm5vdGF0aW9ucwpNYW51YWxseSBhc3NlbWJsZWQgZ2VuZSBhbm5vdGF0aW9ucy4KYGBgCmFubm90IDwtIGMoIkdsdXRhdGhpb25lIE1ldGFib2xpc20iLAogICAgICAgICAgICJQVUZBIiwKICAgICAgICAgICAiRW5kb3NvbWUgRmVyb3VzIFRyYW5zZmVyIiwKICAgICAgICAgICAiRmVycm9wb3J0aW4gRXhwb3J0IiwKICAgICAgICAgICAiQXV0b2x5c29zb21lIEZlcnJpdGluIFN0b3JhZ2UiLAogICAgICAgICAgICJGZXJyaWMgQWNpZCBSZWR1Y3Rpb24iLAogICAgICAgICAgICJIZW1lIElyb24gVHJhbnNmZXIiLAogICAgICAgICAgICJNaXRvY2hvbmRyaWEiKQphbm5vdF9jb2wgPC0gYygib3JhbmdlIiwieWVsbG93IiwiZ3JlZW4iLCJ0dXJxdW9pc2UiLCJwdXJwbGUiLCJyZWQiLCJicm93biIsZ3JleSgwLjUpKQpgYGAKCgpgYGB7cn0KZmVycl9nZW5lc19hbm5vdCA8LSByZWFkLmNzdigiLi4vZGF0YS9mZXJyb3B0b3Npc19nZW5lX2Fubm90LmNzdiIpCmZlcnJfZ2VuZXNfYW5ub3RbZmVycl9nZW5lc19hbm5vdD09IiJdIDwtIE5BCmFubm90cyA8LSB1bmlxdWUodW5saXN0KGFwcGx5KGZlcnJfZ2VuZXNfYW5ub3RbLGdyZXAoImFubm90Iixjb2xuYW1lcyhmZXJyX2dlbmVzX2Fubm90KSldLDIsdW5pcXVlKSkpCmFubm90cyA8LSBhbm5vdHNbYW5ub3RzICE9ICIiICYgIWlzLm5hKGFubm90cyldCmFubm90c19jb2wgPC0gYygieWVsbG93IiwicHVycGxlIixncmV5KDAuNSksImJsYWNrIiwicmVkIiwib3JhbmdlIiwiZ3JlZW4iLCJ0dXJxdW9pc2UiLCJicm93biIpCm5hbWVzKGFubm90c19jb2wpIDwtIGFubm90cwoKZGF0IDwtIEZlcnJfZm9sZFtvcmRlcihtYXRjaChGZXJyX2ZvbGQkR2VuZSxmZXJyX2dlbmVzX2Fubm90JGdlbmVfbmFtZSkpLF0KCmZlciA8LSBsaXN0KGdlbmVzPUZlcnJfZm9sZCRHZW5lLCAKICAgICAgICAgICAgZm9sZF9leHA9ZGF0WywxOjZdLCAKICAgICAgICAgICAgYW5ub3QxPWZlcnJfZ2VuZXNfYW5ub3RbbWF0Y2goZGF0JEdlbmUsZmVycl9nZW5lc19hbm5vdCRnZW5lX25hbWUpLCJhbm5vdDEiXSwKICAgICAgICAgICAgYW5ub3QyPWZlcnJfZ2VuZXNfYW5ub3RbbWF0Y2goZGF0JEdlbmUsZmVycl9nZW5lc19hbm5vdCRnZW5lX25hbWUpLCJhbm5vdDIiXQogICAgICAgICAgICApCmBgYAoKCgojIyBVc2luZyBgQ29tcGxleEhlYXRtYXAoKWAKYGBge3J9CmlmICghcmVxdWlyZU5hbWVzcGFjZSgiQmlvY01hbmFnZXIiLCBxdWlldGx5PVRSVUUpKQogICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQpCaW9jTWFuYWdlcjo6aW5zdGFsbCgiQ29tcGxleEhlYXRtYXAiKQoKbGlicmFyeShDb21wbGV4SGVhdG1hcCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQpodF9vcHQoCiAgICBsZWdlbmRfdGl0bGVfZ3AgPSBncGFyKGZvbnRzaXplID0gOCwgZm9udGZhY2UgPSAiYm9sZCIpLCAKICAgIGxlZ2VuZF9sYWJlbHNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksIAogICAgaGVhdG1hcF9jb2x1bW5fbmFtZXNfZ3AgPSBncGFyKGZvbnRzaXplID0gOCksCiAgICBoZWF0bWFwX2NvbHVtbl90aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSAxMCksCiAgICBoZWF0bWFwX3Jvd190aXRsZV9ncCA9IGdwYXIoZm9udHNpemUgPSA4KQopCgpodF9saXN0ID0gSGVhdG1hcChhcy5tYXRyaXgoZmVyJGZvbGRfZXhwKSwgbmFtZSA9ICJMb2cyIGZvbGQgZXhwcmVzc2lvbiIsCiAgICAgICAgICAgICAgICAgIHdpZHRoID0gdW5pdCg4LCAiY20iKSwgCiAgICAgICAgICAgICAgICAgIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgcm93X25hbWVzX3NpZGUgPSAibGVmdCIsIHJvd19uYW1lc19ncCA9IGdwYXIoZm9udHNpemUgPSA4KSkgKwogICAgSGVhdG1hcChmZXIkYW5ub3QxLCBuYW1lID0gIkdPOjEiLCBjb2wgPSBhbm5vdHNfY29sLCB3aWR0aCA9IHVuaXQoNSwgIm1tIikpICsgCiAgICBIZWF0bWFwKGZlciRhbm5vdDIsIG5hbWUgPSAiR086MiIsIGNvbCA9IGFubm90c19jb2wsIHdpZHRoID0gdW5pdCg1LCAibW0iKSkKCmh0X2xpc3QKYGBgCgoK